home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 12 / Cream of the Crop 12 (Part II) / Cream of the Crop 12 (Part II).iso / OS2 / V15N04.ZIP / WARPCA.ZIP / WCABSRC.ZIP / FILETOOL.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1996-01-18  |  25.2 KB  |  1,055 lines

  1. // FILETOOL.CPP  -- Functions to manipulate files
  2. #include <classlib\arrays.h>
  3. #include <owl\owlpch.h>
  4. #include <owl\applicat.h>
  5. #include <owl\decframe.h>
  6. #include <owl\textgadg.h>
  7. #include <dir.h>
  8. #include <dos.h>
  9. #include <stdio.h>
  10. #include <io.h>
  11. #include <ctype.h>
  12. #include <cstring.h>
  13. #include <assert.h>
  14. #include "os2api.h"
  15. #include "resource.h"
  16. #include "filentry.h"
  17. #include "filetool.h"
  18.  
  19. int SafeDirectoryCreate(LPSTR lpszDir)
  20. {
  21.     // Create a directory safely.  If directory already exists, will return as well!
  22.     // Assume Disk drive letter in first position. 'C:\GUEST' (and uppercase!)
  23.     char szDir[257];
  24.     char szNewDir[257];
  25.     char szOldDir[257];
  26.  
  27.     LPSTR p;
  28.     int rc;
  29.  
  30.     int nTokenCount = 0;
  31.  
  32.     strcpy(szDir, lpszDir);
  33.  
  34.     strcpy(szNewDir, "");
  35.  
  36.     // Append '\' if not provided for drive letter only (e.g., "C:")
  37.     // This is needed to change directory to a drive letter.
  38.     if(szDir[1] == ':' && strlen(szDir) == 2)
  39.     {
  40.         strcat(szDir, "\\");
  41.     }
  42.  
  43.     rc = chdir(szDir);
  44.     if(rc == 0)
  45.     {
  46.         chdir(szOldDir);
  47.         return TRUE;
  48.     }
  49.  
  50.     char chDisk = toupper(szDir[0]) - 'A' + 1;
  51.  
  52.     rc = getcurdir(chDisk, szOldDir);
  53.     if(rc)
  54.         // Can't create this directory since there is no current dir associated with this disk!
  55.         return FALSE;
  56.  
  57.     p = strtok(szDir, "\\");
  58.     while(TRUE)
  59.     {
  60.         if(p)
  61.         {
  62.             if(nTokenCount == 0)
  63.             {
  64.                 strcat(szNewDir, p);
  65.                 strcat(szNewDir, "\\");
  66.             }
  67.             else if(nTokenCount == 1)
  68.             {
  69.                 strcat(szNewDir, p);
  70.             }
  71.             else
  72.             {
  73.                 strcat(szNewDir, "\\");
  74.                 strcat(szNewDir, p);
  75.             }
  76.             rc = chdir(szNewDir);
  77.             if(rc) // Dir. may not exist, attempt to create it.
  78.             {
  79.                 rc = mkdir(szNewDir);
  80.                 if(rc) // Dir. created failed.
  81.                 {
  82.                     chdir(szOldDir);
  83.                     return FALSE;
  84.                 }
  85.             }
  86.             p = strtok(NULL, "\\");
  87.         }
  88.         else
  89.             break;
  90.         nTokenCount++;
  91.     }
  92.     // Restore old directory
  93.     chdir(szOldDir);
  94.     return TRUE;
  95. }
  96.  
  97. void CleanupArrays()
  98. {
  99.     AllFilesList.Flush(TShouldDelete::Delete);
  100.     CriticalDirsList.Flush(TShouldDelete::Delete);
  101. }
  102.  
  103. LPSTR GetFileSizeAsStr(ULONG ulFileSize)
  104. {
  105.     static string strOut;
  106.  
  107.     char szTemp[40];
  108.  
  109.     if(ulFileSize < 1000)
  110.     {
  111.         strOut = ltoa(ulFileSize, szTemp, 10);
  112.         if(ulFileSize == 1)
  113.             strOut += " byte";
  114.         else
  115.             strOut += " bytes";
  116.     }
  117.     else
  118.     {
  119.         ULONG ulKB = ulFileSize / 1000;
  120.         strOut = ltoa(ulKB, szTemp, 10);
  121.         strOut += " KB";
  122.     }
  123.     return (char *)strOut.c_str();
  124. }
  125.  
  126. int CopyMoveFilePrimitive(TWindow *pParent, string& strDest, string& strSrc, int bIsCopy)
  127. {
  128.     ULONG ulSrcSize;
  129.     char szSrcTimeStamp[40];
  130.  
  131.     ULONG ulDestSize;
  132.     char szDestTimeStamp[40];
  133.  
  134.     string strMsg;
  135.  
  136.     int rc = DoesFileExist((LPSTR)strDest.c_str(), ulDestSize, szDestTimeStamp);
  137.     if(rc)
  138.     {
  139.         rc = DoesFileExist((LPSTR)strSrc.c_str(), ulSrcSize, szSrcTimeStamp);
  140.         if(!rc)
  141.         {
  142.             pParent->MessageBox("Unexpected error. Source file doesn't exist.", "Source File Not Found", MB_ICONEXCLAMATION);
  143.             return FALSE;
  144.         }
  145.  
  146.         if(bConfirmReplace || bConfirmAll)
  147.         {
  148.             strMsg = "Replace file: ";
  149.             strMsg += strDest;
  150.             strMsg += " (";
  151.             strMsg += GetFileSizeAsStr(ulDestSize);
  152.             strMsg += ", ";
  153.             strMsg += szDestTimeStamp;
  154.             strMsg += ")\n    With file: ";
  155.             strMsg += strSrc;
  156.             strMsg += " (";
  157.             strMsg += GetFileSizeAsStr(ulSrcSize);
  158.             strMsg += ", ";
  159.             strMsg += szSrcTimeStamp;
  160.             strMsg += ")?";
  161.  
  162.             rc = pParent->MessageBox((LPSTR)strMsg.c_str(), "Confirm Overwrite", MB_YESNOCANCEL);
  163.             if(rc == IDCANCEL)
  164.                 return -5;  // Tell caller to abort!
  165.             else if(rc == IDNO)
  166.                 return FALSE;
  167.         }
  168.     }
  169.  
  170.     if(bIsCopy)
  171.     {
  172.         // To here, copy source and target files.
  173.         rc = DosCopy(strSrc.c_str(), strDest.c_str(), 5);  // DCPY_EXISTING | DCPY_FAILAS
  174.         if(rc)
  175.         {
  176.             if(rc == 112)
  177.                 strMsg = "Error copying file (Out of disk space?): ";
  178.             else
  179.                 strMsg = "Error copying file: ";
  180.             strMsg += strSrc;
  181.             strMsg += "\n to ";
  182.             strMsg += strDest;
  183.             strMsg += ".";
  184.             pParent->MessageBox((LPSTR)strMsg.c_str(), "Can't Copy File", MB_ICONEXCLAMATION);
  185.             return FALSE;
  186.         }
  187.     }
  188.     else
  189.     {
  190.         // Then we're moving
  191.         rc = DosCopy(strSrc.c_str(), strDest.c_str(), 5);  // DCPY_EXISTING | DCPY_FAILAS
  192.         if(rc)
  193.         {
  194.             if(rc == 112)
  195.                 strMsg = "Error moving file (Out of disk space?): ";
  196.             else if(rc == 250)
  197.                 strMsg = "Error moving file (Parent can't be moved to its own subdirectory!): ";
  198.             else
  199.                 strMsg = "Error moving file: ";
  200.             strMsg += strSrc;
  201.             strMsg += "\n to ";
  202.             strMsg += strDest;
  203.             strMsg += ".";
  204.             pParent->MessageBox((LPSTR)strMsg.c_str(), "Can't Move File", MB_ICONEXCLAMATION);
  205.             return FALSE;
  206.         }
  207.         else
  208.         {
  209.             // We need to unlink after we copy.
  210.             rc = _rtl_chmod(strSrc.c_str(), 1, FA_ARCH);
  211.             if(!rc)
  212.                 rc = unlink((LPSTR)strSrc.c_str());
  213.             if(rc)
  214.             {
  215.                 strMsg = "Can't remove file on source: ";
  216.                 strMsg += strSrc;
  217.                 strMsg += ".  This file may be in use by another process.";
  218.                 pParent->MessageBox((LPSTR)strMsg.c_str(), "Can't Remove Source File", MB_ICONEXCLAMATION);
  219.                 return FALSE;
  220.             }
  221.         }
  222.     }
  223.     return TRUE;
  224. }
  225.  
  226. int CopyOrMoveFiles(FILEOPPARAM *pParam)
  227. {
  228.     PFILEOPPARAM pFileOpParam = (PFILEOPPARAM)pParam;
  229.  
  230.     int nFileOp = pFileOpParam->nFileOp;
  231.     TTextGadget *pStatus = pFileOpParam->pStatus;
  232.     HWND hwndStatus = pFileOpParam->hwndStatus;
  233.     TWindow *pParent = pFileOpParam->pParent;
  234.  
  235.     char szSourceDir[257];
  236.     strcpy(szSourceDir, pFileOpParam->lpszSourceDir);
  237.  
  238.     char szTargetDir[257];
  239.     strcpy(szTargetDir, pFileOpParam->lpszTargetDir);
  240.  
  241.     char szTargetFile[257];
  242.     if(pFileOpParam->lpszTargetFile)
  243.         strcpy(szTargetFile, pFileOpParam->lpszTargetFile);
  244.     else
  245.         szTargetFile[0] = 0;
  246.  
  247.     string strTarget;
  248.     string strSource;
  249.     string strMsg;
  250.  
  251.     int i;
  252.     int rc;
  253.  
  254.     if(pStatus)
  255.         pStatus->SetText("Creating subdirectories...");
  256.     if(hwndStatus)
  257.         WinSetWindowText(hwndStatus, "Creating subdirectories...");
  258.     if(pParent)
  259.         pParent->UpdateWindow();
  260.     rc = SafeDirectoryCreate(szTargetDir);
  261.     if(!rc)
  262.     {
  263.         strMsg = "Unable to create ";
  264.         strMsg += szTargetDir;
  265.         pParent->MessageBox((LPSTR)strMsg.c_str(), "Can't Create Directory", MB_ICONSTOP);
  266.         CleanupArrays();
  267.         return FALSE;
  268.     }
  269.  
  270.     int nDirs = CriticalDirsList.GetItemsInContainer();
  271.     if(nDirs > 0)
  272.     {
  273.         for(i = 0; i < nDirs; i++)
  274.         {
  275.             strTarget = szTargetDir;
  276.             strTarget += *CriticalDirsList[i];
  277. #ifdef _TESTING_
  278.             pParent->MessageBox(strTarget.c_str(), "Creating Dir.", MB_OK);
  279. #endif
  280.             rc = SafeDirectoryCreate((LPSTR)strTarget.c_str());
  281.             if(!rc)
  282.             {
  283.                 strMsg = "Unable to create ";
  284.                 strMsg += strTarget.c_str();
  285.                 pParent->MessageBox((LPSTR)strMsg.c_str(), "Can't Create Directory", MB_ICONSTOP);
  286.                 CleanupArrays();
  287.                 return FALSE;
  288.             }
  289.         }
  290.     }
  291.  
  292.     // Now copy or move files...
  293.     string *pStr;
  294.  
  295.     int bIsCopy = nFileOp == CM_COPY ? TRUE : FALSE;
  296.  
  297.     int bUseFileMask = strlen(szTargetFile) > 0 ? TRUE : FALSE;
  298.  
  299.     string strTargetFileMask = szTargetFile;
  300.  
  301.     for(i = 0; i < AllFilesList.GetItemsInContainer(); i++)
  302.     {
  303.         strSource = szSourceDir;
  304.         strSource += *AllFilesList[i];
  305.  
  306.         strTarget = szTargetDir;
  307.         strTarget += *AllFilesList[i];
  308.  
  309.         string strErrMsg;
  310.         string strNewTarget;
  311.  
  312.         if(bUseFileMask)
  313.         {
  314.             rc = MakeNewSourcePathWithWildcardMask(strNewTarget, strSource, strTargetFileMask, strErrMsg);
  315.             if(!rc)
  316.             {
  317.                 strMsg = "Can't make new target filename (Error = ";
  318.                 strMsg += strErrMsg;
  319.                 strMsg += ") Continue?";
  320.                 rc = pParent->MessageBox((LPSTR)strMsg.c_str(), "Bad Filename", MB_ICONEXCLAMATION | MB_YESNOCANCEL);
  321.                 if(rc != IDYES)
  322.                     break;
  323.                 else
  324.                     continue;
  325.             }
  326.             strTarget = strNewTarget;
  327.         }
  328.  
  329.         if(nFileOp == CM_COPY)
  330.             strMsg = "Copying to file ";
  331.         else
  332.             strMsg = "Moving file to ";
  333.         strMsg += strTarget;
  334.         strMsg += "...";
  335.         if(pStatus)
  336.             pStatus->SetText(strMsg.c_str());
  337.         if(hwndStatus)
  338.             WinSetWindowText(hwndStatus, (LPSTR)strMsg.c_str());
  339.         if(pParent)
  340.             pParent->UpdateWindow();
  341.         rc = CopyMoveFilePrimitive(pParent, strTarget, strSource, bIsCopy);
  342.         if(rc == -5)
  343.             return FALSE;  // Stop processing, user has stopped on an error.
  344.     }
  345.  
  346.     // Lastly, if we're moving, delete our "empty" directory tree.
  347.     if(nFileOp == CM_MOVE)
  348.     {
  349.         int nDirs = CriticalDirsList.GetItemsInContainer();
  350.         if(nDirs > 0)
  351.         {
  352.             if(pStatus)
  353.                 pStatus->SetText("Cleaning-up directories...");
  354.             if(hwndStatus)
  355.                 WinSetWindowText(hwndStatus, "Cleaning-up directories...");
  356.             if(pParent)
  357.                 pParent->UpdateWindow();
  358.             // Ensure correct working directory.
  359.             chdir(szSourceDir);
  360.             for(i = nDirs - 1; i >= 0; i--)  // A trick, doing these backwards should clean out an empty directory.
  361.             {
  362.                 strSource = szSourceDir;
  363.                 strSource += *CriticalDirsList[i];
  364. #ifdef _TESTING_
  365.                 pParent->MessageBox(strSource.c_str(), "Deleting (Empty) Dir.", MB_OK);
  366. #endif
  367.                 rc = rmdir((LPSTR)strSource.c_str());
  368. #ifdef _TESTING_
  369.                 if(!rc)
  370.                 {
  371.                     strMsg = "Unable to remove ";
  372.                     strMsg += strSource.c_str();
  373.                     strMsg += " This directory might not be empty. Continue anyway?";
  374.                     rc = pParent->MessageBox((LPSTR)strMsg.c_str(), "Can't Remove Directory", MB_YESNOCANCEL);
  375.                     if(rc != IDYES)
  376.                     {
  377.                         CleanupArrays();
  378.                         return FALSE;
  379.                     }
  380.                 }
  381. #endif
  382.             }
  383.         }
  384.     }
  385.     return TRUE;  // Success!
  386. }
  387.  
  388. int DeleteFiles(FILEOPPARAM *pParam)
  389. {
  390.     PFILEOPPARAM pFileOpParam = (PFILEOPPARAM)pParam;
  391.  
  392.     int nFileOp = pFileOpParam->nFileOp;
  393.  
  394.     assert(nFileOp == CM_DELETE);
  395.  
  396.     TTextGadget *pStatus = (TTextGadget *)pFileOpParam->pStatus;
  397.     HWND hwndStatus = pFileOpParam->hwndStatus;
  398.     TWindow *pParent = pFileOpParam->pParent;
  399.     char szSourceDir[257];
  400.     strcpy(szSourceDir, pFileOpParam->lpszSourceDir);
  401.  
  402.     string strDeleteSource;
  403.     string strMsg;
  404.  
  405.     int nRetVal;
  406.  
  407.     // Now copy or move files...
  408.     string *pStr;
  409.  
  410.     int bSpecialFile = FALSE;
  411.     int i;
  412.     int rc;
  413.  
  414.     struct ffblk FileInfo;
  415.  
  416.     for(i = 0; i < AllFilesList.GetItemsInContainer(); i++)
  417.     {
  418.         strDeleteSource = szSourceDir;
  419.         strDeleteSource += *AllFilesList[i];
  420.  
  421.         bSpecialFile = FALSE;
  422.  
  423.         strMsg = "Deleting file ";
  424.         strMsg += strDeleteSource;
  425.         strMsg += "...";
  426.         if(pStatus)
  427.             pStatus->SetText(strMsg.c_str());
  428.         if(hwndStatus)
  429.             WinSetWindowText(hwndStatus, (LPSTR)strMsg.c_str());
  430.         if(pParent)
  431.             pParent->UpdateWindow();
  432.         rc = findfirst(strDeleteSource.c_str(), &FileInfo, 0);
  433.         if(rc)
  434.         {
  435.             strMsg = "Can't find file ";
  436.             strMsg += strDeleteSource;
  437.             strMsg += ". Continue anyway?";
  438.             rc = pParent->MessageBox(strMsg.c_str(), "File Not Found", MB_YESNOCANCEL);
  439.             if(rc == IDCANCEL)
  440.             {
  441.                 CleanupArrays();
  442.                 return FALSE;
  443.             }
  444.             else if(rc == IDYES)
  445.             {
  446.                 // Skip to next file.
  447.                 continue;
  448.             }
  449.         }
  450.         else // Check for system or hidden or read-only file
  451.         {
  452.             if((FileInfo.ff_attrib & FA_RDONLY) != 0 ||
  453.                 (FileInfo.ff_attrib & FA_SYSTEM) != 0 ||
  454.                 (FileInfo.ff_attrib & FA_HIDDEN) != 0)
  455.             {
  456.                 bSpecialFile = TRUE;
  457.  
  458.                 strMsg = "This is a hidden/read-only/or system file. Delete ";
  459.                 strMsg += strDeleteSource;
  460.                 strMsg += " anyway?";
  461.                 rc = pParent->MessageBox(strMsg.c_str(), "Confirm Delete", MB_YESNOCANCEL);
  462.                 if(rc == IDCANCEL)
  463.                 {
  464.                     CleanupArrays();
  465.                     return FALSE;
  466.                 }
  467.                 else if(rc == IDNO)
  468.                 {
  469.                     // Skip to next file.
  470.                     continue;
  471.                 }
  472.             }
  473.         }
  474.  
  475.         if(bSpecialFile)
  476.         {
  477.             // Change attrib. to normal, archive file.
  478.             nRetVal = _rtl_chmod(strDeleteSource.c_str(), 1, FA_ARCH);
  479.             rc = nRetVal == -1 ? FALSE : TRUE;
  480.         }
  481.         else
  482.             rc = TRUE;
  483.  
  484.         if(rc)
  485.         {
  486.             nRetVal = unlink(strDeleteSource.c_str());
  487.             rc = nRetVal ? FALSE : TRUE;
  488.         }
  489.  
  490.         if(!rc)
  491.         {
  492.             strMsg = "Unable to delete file ";
  493.             strMsg += strDeleteSource;
  494.             strMsg += ". (It may be in-use by another application,) Continue?";
  495.             rc = pParent->MessageBox(strMsg.c_str(), "Can't Delete", MB_YESNOCANCEL);
  496.             if(rc == IDCANCEL)
  497.             {
  498.                 CleanupArrays();
  499.                 return FALSE;
  500.             }
  501.             else if(rc == IDNO)
  502.             {
  503.                 // Skip to next file.
  504.                 continue;
  505.             }
  506.         }
  507.     }
  508.  
  509.     // Lastly, delete our "empty" directory tree.
  510.     if(nFileOp == CM_MOVE || nFileOp == CM_DELETE)
  511.     {
  512.         int nDirs = CriticalDirsList.GetItemsInContainer();
  513.         if(nDirs > 0)
  514.         {
  515.             if(pStatus)
  516.                 pStatus->SetText("Cleaning-up directories...");
  517.             if(hwndStatus)
  518.                 WinSetWindowText(hwndStatus, "Cleaning-up directories...");
  519.             if(pParent)
  520.                 pParent->UpdateWindow();
  521.             // Ensure correct working directory.
  522.             chdir(szSourceDir);
  523.             for(i = nDirs - 1; i >= 0; i--)  // A trick, doing these backwards should clean out an empty directory.
  524.             {
  525.                 strDeleteSource = szSourceDir;
  526.                 strDeleteSource += *CriticalDirsList[i];
  527. #ifdef _TESTING_
  528.                 pParent->MessageBox(strDeleteSource.c_str(), "Deleting (Empty) Dir.", MB_OK);
  529. #endif
  530.                 rc = DosDeleteDir(strDeleteSource.c_str());
  531. #ifdef _TESTING_
  532.                 if(rc)
  533.                 {
  534.                     strMsg = "Unable to remove ";
  535.                     strMsg += strDeleteSource.c_str();
  536.                     strMsg += " This directory might not be empty. Continue anyway?";
  537.                     rc = pParent->MessageBox((LPSTR)strMsg.c_str(), "Can't Remove Directory", MB_YESNOCANCEL);
  538.                     if(rc != IDYES)
  539.                     {
  540.                         CleanupArrays();
  541.                         return FALSE;
  542.                     }
  543.                 }
  544. #endif
  545.             }
  546.         }
  547.     }
  548.     return TRUE;  // Success!
  549. }
  550.  
  551. BOOL DoesFileExist(LPSTR lpszThisFile, ULONG& ulSize, LPSTR lpszTimeStamp)
  552. {
  553.     struct ffblk FileInfo;
  554.  
  555.     int rc = findfirst(lpszThisFile, &FileInfo, 0);
  556.  
  557.     if(rc)
  558.         return FALSE;
  559.     else
  560.     {
  561.         // Get old file so we can get the user to confirm over-writes...
  562.         ulSize = FileInfo.ff_fsize;
  563.         if(lpszTimeStamp)
  564.             GetFileTimeStampAsString(lpszTimeStamp, FileInfo.ff_fdate, FileInfo.ff_ftime);
  565.         return TRUE;
  566.     }
  567. }
  568.  
  569. LPSTR GetFileTimeStampAsString(LPSTR lpszDateTime, unsigned short int uFileDate, unsigned short int uFileTime)
  570. {
  571.     char szStamp[256];
  572.  
  573.     // Unpack file timestamp.
  574.     int nSec = (uFileTime % 32) * 2;    // 0 - 4    Number of 2-second increments (0 - 29).
  575.     int nMin = (uFileTime >> 5) % 64;   // 5 - 10     Minutes (0 - 59)
  576.     int nHour = uFileTime >> 11;        // 11 - 15     Hours (0 - 23)
  577.  
  578.     int nDay = uFileDate % 32;                // 0 - 4    Day of month (1-31)
  579.     int nMonth = (uFileDate >> 5) % 16; // 5 - 8    Month (1-12)
  580.     int nYear = (uFileDate >> 9) + 80;  // 9 - 15   Year (relative to 1980)
  581.  
  582.     // Format.
  583.     int bIsPM = FALSE;
  584.     if(nHour >= 12)
  585.     {
  586.         bIsPM = TRUE;
  587.         nHour -= 12;
  588.         if(nHour == 0)
  589.             nHour = 12;
  590.     }
  591.     wsprintf(szStamp, "%2d/%02d/%02d %2d:%02d:%02d %s\0", nMonth, nDay, nYear, nHour, nMin, nSec, bIsPM ? "PM" : "AM");
  592.  
  593.     strcpy(lpszDateTime, szStamp);
  594.  
  595.     return lpszDateTime;
  596. }
  597.  
  598. int RemoveSourceDirFromPath(string& strResultPath, string& strRawPath, string& strSourceDir)
  599. {
  600.     int nRetVal = FALSE;
  601.     string strCriticalDir("");
  602.     // strRawPath contains full path--Find source dir inside this.
  603.     // If found, copy only the 'critical' part of path
  604.     size_t rc = strRawPath.find_first_of(strSourceDir);
  605.     if(rc != NPOS)
  606.     {
  607.         // Then get 'critical' dir above the source dir.
  608.         strCriticalDir = strRawPath.substr(rc + strSourceDir.length());
  609.         if(strCriticalDir.length() > 0)
  610.         {
  611.             strResultPath = strCriticalDir;
  612.             nRetVal = TRUE;
  613.         }
  614.     }
  615.     return nRetVal;
  616. }
  617.  
  618. int CollectAllFilesInSelections(LPSTR lpszThisDir, LPSTR lpszMask, ULONG ulAttrs, LPSTR lpszSourceDir)
  619. {
  620.     // Copies selected file list into all files array.  Walks through sub-dir trees too
  621.     // using current mask and selected attributes.
  622.     ulTotalFilesBytes = 0;
  623.  
  624.     AllFilesList.Flush(TShouldDelete::Delete);  // Make sure total files array is empty.
  625.     CriticalDirsList.Flush(TShouldDelete::Delete);  // Make sure total dir. array is empty.
  626.  
  627.     FILEENTRY *pThisEntry = NULL;
  628.  
  629.     string strNewFile;
  630.  
  631.     string strFullDir = lpszThisDir;
  632.     string strThisDir;
  633.  
  634.     for(int i = 0; i < SelectedFileList.GetItemsInContainer(); i++)
  635.     {
  636.         pThisEntry = SelectedFileList[i];
  637.  
  638.         if(!pThisEntry)
  639.             continue;
  640.  
  641.         if(pThisEntry->nType == 1)  // If it's a directory, get all files in tree.
  642.         {
  643.             strThisDir = strFullDir;
  644.  
  645.             strThisDir = "\\";
  646.             strThisDir += pThisEntry->szFileName;
  647.  
  648.             CriticalDirsList.Add(new string(strThisDir));
  649.  
  650.             strThisDir = strFullDir;
  651.             strThisDir += "\\";
  652.             strThisDir += pThisEntry->szFileName;
  653.  
  654.             LoadFilesInDir((char *)strThisDir.c_str(), lpszMask, ulAttrs, lpszSourceDir);
  655.         }
  656.         else
  657.         {
  658.             // Just add this file to complete list.
  659.             ulTotalFilesBytes += (ULONG)pThisEntry->lFileSize;
  660.             strNewFile = "\\";
  661.             strNewFile += pThisEntry->szFileName;
  662.             AllFilesList.Add(new string(strNewFile));
  663.         }
  664.     }
  665.     return AllFilesList.GetItemsInContainer();
  666. }
  667.  
  668.  
  669. // Scan this directory for all files and sub-directories.
  670. // This method can be called recursively.  Writes results to AllFilesList global array.
  671. int LoadFilesInDir(LPSTR lpszThisDir, LPSTR lpszMask, ULONG ulAttrs, LPSTR lpszSourceDir)
  672. {
  673.     BOOL bFirstTime;
  674.  
  675.     struct ffblk FileInfo;
  676.  
  677.     int i;
  678.     int rc;
  679.  
  680.     // Build search directory.
  681.     string strSearchDir = lpszThisDir;
  682.     strSearchDir += "\\*.*";
  683.  
  684.     string strSourceDir(lpszSourceDir);
  685.  
  686.     string strPath;
  687.     string strCriticalDir;
  688.  
  689.     //string strFullPath = strSourceDir + strSearchDir;
  690.  
  691.     char szNewDir[257];
  692.  
  693.     unsigned long ulSearchBits = ulAttrs;
  694.  
  695.     TISArrayAsVector <string> DirList(4,0,1);  // Store our directories in this path
  696.                                                     // This must be local to this procedure so
  697.                                                     // we can recurse levels of sub-dirs!
  698.  
  699.     // Hunt down all directories and files that match selected attributes.
  700.     bFirstTime = TRUE;
  701.     while(1)
  702.     {
  703.         if(bFirstTime)
  704.         {
  705.             rc = findfirst(strSearchDir.c_str(), &FileInfo, FA_DIREC);
  706.             bFirstTime = FALSE;
  707.         }
  708.         else
  709.             rc = findnext(&FileInfo);
  710.         if(rc)
  711.             break;  // We're finished
  712.  
  713.         // Otherwise we might have a match.
  714.         // Check to see if it's a directory and if so, make sure that
  715.         // if its hidden, system or read-only, these bits are selected as well.
  716.         if((FileInfo.ff_attrib & FA_DIREC) == FA_DIREC && (FileInfo.ff_name[0] != '.'))
  717.         {
  718.             if(ulSearchBits > 0)
  719.                 if((ulSearchBits & FileInfo.ff_attrib) == 0)
  720.                     continue;
  721.             // To here, add this directory name to our array.
  722.             strPath = lpszThisDir;
  723.             strPath += "\\";
  724.             strPath += FileInfo.ff_name;
  725.  
  726.             // strPath contains full path--Find source dir inside this.
  727.             // If found, copy only the 'critical' part of path
  728.             rc = RemoveSourceDirFromPath(strCriticalDir, strPath, strSourceDir);
  729.             if(rc && strCriticalDir.length() > 0)
  730.             {
  731.                 CriticalDirsList.Add(new string(strCriticalDir));
  732.             }
  733. #ifdef _TESTING_
  734.             else
  735.                 assert(0);
  736. #endif
  737.             DirList.Add(new string(strPath));
  738.         }
  739.     }
  740.  
  741.     // Now get files in the current directory.  These are collected in global!!!
  742.     bFirstTime = TRUE;
  743.  
  744.     strSearchDir = lpszThisDir;
  745.     strSearchDir += "\\";
  746.     strSearchDir += lpszMask;
  747.  
  748.     while(1)
  749.     {
  750.         if(bFirstTime)
  751.         {
  752.             rc = findfirst(strSearchDir.c_str(), &FileInfo, 0);
  753.             bFirstTime = FALSE;
  754.         }
  755.         else
  756.             rc = findnext(&FileInfo);
  757.         if(rc)
  758.             break;  // We're finished
  759.  
  760.         // Otherwise we might have a match.
  761.         // Check to see if it's a directory.  If not, make sure that
  762.         // if its hidden, system or read-only, these bits are selected as well.
  763.         if((FileInfo.ff_attrib & FA_DIREC) == FA_DIREC)
  764.             continue;
  765.         if(ulSearchBits > 0)
  766.             if((ulSearchBits & FileInfo.ff_attrib) == 0)
  767.                 continue;
  768.         // To here, add this file information to our array.
  769.         // This will be automatically sorted!
  770.         strPath = lpszThisDir;
  771.         strPath += "\\";
  772.         strPath += FileInfo.ff_name;
  773.  
  774.         ulTotalFilesBytes += (ULONG)FileInfo.ff_fsize;
  775.  
  776.         rc = RemoveSourceDirFromPath(strPath, strPath, strSourceDir);
  777.         if(rc)
  778.         {
  779. #ifdef _TESTING_
  780.             pGlobalParent->MessageBox((LPSTR)strPath.c_str(), "Adding File:", MB_OK);
  781. #endif
  782.             AllFilesList.Add(new string(strPath));
  783.         }
  784. #ifdef _TESTING_
  785.         else
  786.             assert(0);
  787. #endif
  788.     }
  789.  
  790.     // Now the tricky part.
  791.     // Walk through directory array and process each entry with this same function.
  792.     string *pThisDir = NULL;
  793.  
  794.     for(i = 0; i < DirList.GetItemsInContainer(); i++)
  795.     {
  796.         pThisDir = DirList[i];
  797.         if(pThisDir)
  798.         {
  799.             // Build new path for receiver.
  800.             strcpy(szNewDir, pThisDir->c_str());
  801.  
  802.             // Recursion -- make sure our stack is large enough.
  803.             rc = LoadFilesInDir(szNewDir, lpszMask, ulAttrs, lpszSourceDir);
  804.         }
  805.     }
  806.  
  807.     // Clean-up our linked list.
  808.     DirList.Flush(TShouldDelete::Delete);
  809.  
  810.     return TRUE;
  811. }
  812.  
  813. int MakeNewSourcePathWithWildcardMask(string& strNewFullSourcePath, string& strOldFullSourcePath,
  814.                                                   string& strWildcardMask, string& strErrMsg)
  815. {
  816.     strErrMsg = "";
  817.  
  818.     string strRawFileOnly("");
  819.     string strRawDirOnly("");
  820.     string strNewFile("");
  821.  
  822.     strNewFullSourcePath = "";
  823.  
  824.     string strSlash("\\");
  825.  
  826.     size_t p;
  827.  
  828.     p = strOldFullSourcePath.find_last_of(strSlash);
  829.     if(p != NPOS)
  830.     {
  831.         strRawFileOnly = strOldFullSourcePath.substr(p + 1);
  832.         strRawDirOnly = strOldFullSourcePath.substr(0, p + 1);
  833.     }
  834.     else
  835.     {
  836.         strErrMsg = "Missing full directory in source.";
  837.         return FALSE;
  838.     }
  839.  
  840.     // Now meld wildcard in mask with file to get new filename.
  841.     int bPeriodFound = FALSE;
  842.  
  843.     string chMask("");
  844.     string chSource("");
  845.  
  846.     string strPeriod(".");
  847.  
  848.     int bNoPeriodInSource = FALSE;
  849.  
  850.     int nSourceMarker = 0;
  851.  
  852.     try
  853.     {
  854.  
  855.         for(int i = 0; i < strWildcardMask.length() && (nSourceMarker < strRawFileOnly.length() || bNoPeriodInSource); i++)
  856.         {
  857.             chMask = strWildcardMask.substr(i, 1);
  858.  
  859.             if(chMask == "?")
  860.             {
  861.                 if(bNoPeriodInSource)
  862.                     break;
  863.                 chSource = strRawFileOnly.substr(nSourceMarker, 1);
  864.                 strNewFile += chSource;
  865.                 nSourceMarker++;
  866.             }
  867.             else if(chMask == "*")
  868.             {
  869.                 if(bNoPeriodInSource)
  870.                     break;
  871.                 if(bPeriodFound)
  872.                 {
  873.                     // Then take rest of source file.
  874.                     strNewFile += strRawFileOnly.substr(nSourceMarker);
  875.                     break;  // We must be done.
  876.                 }
  877.                 else  // Then take source file to period or rest of string if no period is found.
  878.                 {
  879.                     p = strRawFileOnly.find_first_of(strPeriod);
  880.                     if(p == NPOS)
  881.                     {
  882.                         strNewFile += strRawFileOnly.substr(nSourceMarker);
  883.                         nSourceMarker = p;
  884.                         bNoPeriodInSource = TRUE;
  885.                     }
  886.                     else
  887.                     {
  888.                         strNewFile += strRawFileOnly.substr(nSourceMarker, p - nSourceMarker);
  889.                         p = strWildcardMask.find_first_of(strPeriod);
  890.                         if(p != NPOS)
  891.                             i = p - 1;
  892.                         else
  893.                             break;  // No period means there nothing else to add
  894.                     }
  895.                 }
  896.             }
  897.             else if(chMask == ".")
  898.             {
  899.                 if(bPeriodFound)
  900.                 {
  901.                     strErrMsg = "Invalid target filename";
  902.                     return FALSE;
  903.                 }
  904.                 else
  905.                 {
  906.                     strNewFile += ".";
  907.                     // Move past "." in source
  908.                     p = strRawFileOnly.find_first_of(strPeriod);
  909.                     if(p != NPOS)
  910.                         nSourceMarker = p + 1;
  911.                     else
  912.                         bNoPeriodInSource = TRUE;
  913.                     bPeriodFound = TRUE;
  914.                 }
  915.             }
  916.             else
  917.             {
  918.                 // Write in mask into target file.
  919.                 strNewFile += chMask;
  920.                 nSourceMarker++;
  921.             }
  922.         }
  923.     }
  924.     catch(...)
  925.     {
  926.         strErrMsg = "Bad mask or source file.";
  927.         strNewFullSourcePath = "";
  928.         return FALSE;
  929.     }
  930.     strNewFullSourcePath = strRawDirOnly + strNewFile;
  931.     return TRUE;
  932. }
  933.  
  934. int ChangeFileAttributes(LPSTR lpszCurrentDir, ULONG ulNewAttrib)
  935. {
  936.     // Change attributes for this list of files.
  937.     FILEENTRY *pFileEntry;
  938.  
  939.     string strMsg;
  940.  
  941.     int bFilePropSet;
  942.  
  943.     if(pGlobalParent)
  944.         pGlobalParent->SetCursor(0, IDC_WAIT);
  945.  
  946.     if(pGlobalStatusBar)
  947.         pGlobalStatusBar->SetText("Changing attributes...");
  948.  
  949.     int rc;
  950.  
  951.     for(int i = 0; i < SelectedFileList.GetItemsInContainer(); i++)
  952.     {
  953.         string szThisFile;
  954.  
  955.         bFilePropSet = FALSE;
  956.         pFileEntry = (FILEENTRY *)SelectedFileList[i];
  957.         if(pFileEntry)
  958.         {
  959.             szThisFile = lpszCurrentDir;
  960.             szThisFile += "\\";
  961.             szThisFile += pFileEntry->szFileName;
  962.             rc = _rtl_chmod((LPSTR)szThisFile.c_str(), 1, ulNewAttrib);
  963.             if(!rc)
  964.                 bFilePropSet = TRUE;
  965.         }
  966.  
  967.         if(!bFilePropSet)
  968.         {
  969.             if(!pGlobalParent)
  970.                 break;
  971.             strMsg = "Can't set attributes for file: ";
  972.             strMsg += pFileEntry->szFileName;
  973.             strMsg += ". Continue anyway?";
  974.             rc = pGlobalParent->MessageBox((LPSTR)strMsg.c_str(), "Can't Set Properties", MB_YESNOCANCEL | MB_ICONEXCLAMATION);
  975.             if(rc != IDYES)
  976.                 break;
  977.             else
  978.                 if(pGlobalParent)
  979.                     pGlobalParent->SetCursor(0, IDC_WAIT);
  980.  
  981.         }
  982.     }
  983.     if(pGlobalStatusBar)
  984.         pGlobalStatusBar->SetText("");
  985.  
  986.     if(pGlobalParent)
  987.         pGlobalParent->SetCursor(0, IDC_ARROW);
  988.  
  989.     return TRUE;
  990. }
  991.  
  992. BOOL RunProgramWithArgs(LPSTR lpszExeName, LPSTR lpszArgs)
  993. {
  994.     STARTDATA   StartData;
  995.     ULONG       SessID;
  996.     PID         PID;
  997.     UCHAR       PgmName[256]; // Program pathname string
  998.     UCHAR       PgmArgs[256]; // Arguments
  999.     UCHAR       ObjBuf[100];
  1000.     int rc;
  1001.  
  1002.     //  Specify the various session start parameters
  1003.     StartData.Length = sizeof(STARTDATA);
  1004.     StartData.Related =  SSF_RELATED_INDEPENDENT;  // New session.
  1005.     StartData.FgBg = SSF_FGBG_FORE;                      // Run in foreground.
  1006.     StartData.TraceOpt = SSF_TRACEOPT_NONE;
  1007.  
  1008.     StartData.PgmTitle = 0;
  1009.  
  1010.     strcpy(PgmName, lpszExeName);
  1011.     StartData.PgmName = PgmName;
  1012.  
  1013.     if(lpszArgs)
  1014.     {
  1015.         strcpy(PgmArgs, lpszArgs); // Arguments
  1016.         StartData.PgmInputs = PgmArgs;
  1017.     }
  1018.     else
  1019.         StartData.PgmInputs = 0;
  1020.  
  1021.     StartData.TermQ = 0;
  1022.     StartData.Environment = 0;
  1023.     StartData.InheritOpt = 0;
  1024.  
  1025.     StartData.SessionType = SSF_TYPE_DEFAULT;
  1026.  
  1027.     StartData.IconFile = 0;
  1028.     StartData.PgmHandle = 0;
  1029.  
  1030.     StartData.PgmControl = SSF_CONTROL_VISIBLE;
  1031.  
  1032.     StartData.InitXPos = 0;
  1033.     StartData.InitYPos = 0;
  1034.     StartData.InitXSize = 0;
  1035.     StartData.InitYSize = 0;
  1036.  
  1037.     StartData.Reserved = 0;
  1038.  
  1039.     StartData.ObjectBuffer = ObjBuf;
  1040.     StartData.ObjectBuffLen = 100;
  1041.  
  1042.     rc = DosStartSession(&StartData, &SessID, &PID);
  1043.     if (rc != 0)
  1044.     {
  1045.         return FALSE;
  1046.     }
  1047.     else
  1048.     {
  1049.         return TRUE;
  1050.     }
  1051. }
  1052.  
  1053.  
  1054.  
  1055.